﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Dtd.Schema;
using System.Diagnostics;
using Engine.Sgml.Validation;
using Engine.Sgml.Allocation;
using Engine.Sgml.Merging;

namespace Engine.Sgml {
    [DebuggerNonUserCode]
    internal static class TraceSourceExtention {

        public static void TraceError(this TraceSource ts, string message, params object[] args) {
            Debug.Assert(ts != null);
            ts.TraceEvent(TraceEventType.Error, 0, message, args);
            }

        public static void TraceWarning(this TraceSource ts, string message, params object[] args) {
            Debug.Assert(ts != null);
            ts.TraceEvent(TraceEventType.Warning, 0, message, args);
            }

        public static void TraceInconsistentBlock(this TraceSource ts, InconsistentBlock block) {
            Debug.Assert(ts != null);
            for (int i = 0; i < block.Count; i++)
                ts.TraceEvent(TraceEventType.Error, 0, "Element '{0}' can not be nested in ({1}) whithin '{2}' ({3}).", GetElementName(block[i]), block[i].Context(), block.Ancestor.Name.ToString(), block.Ancestor.Context());
            }

        public static void TraceMoveElement(this TraceSource ts, SElement element, SElement moved, int position) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Move '{0}' ({1}) to position {4} in '{2}' ({3}) element.", moved.Name.ToString(), moved.Context(), element.Name.ToString(), element.Context(), position);
            }

        public static void TraceMoveElement(this TraceSource ts, SElement element, int position) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Move '{0}' ({1}) from {2} to {3} position.", element.Name.ToString(), element.Context(), element.OrderIndex, position);
            }

        public static void TraceInsertElement(this TraceSource ts, SElement element) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Insert '{0}' ({1}).", element.Name.ToString(), element.Context());
            }

        public static void TraceRemoveElement(this TraceSource ts, SElement element) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Remove '{0}' ({1}).", element.Name.ToString(), element.Context());
            }

        public static void TraceSuccessAllocation(this TraceSource ts, SElement element) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Allocate '{0}' ({1}) element in '{2}' ({3}).", element.Name.ToString(), element.Context(), element.Parent.Name.ToString(), element.Parent.Context());
            }

        public static void TraceFailureAllocation(this TraceSource ts, SElement element) {
            Debug.Assert(ts != null);
            ts.TraceEvent(TraceEventType.Warning, 0, "Failure allocate element '{0}' ({1}).", element.Name.ToString(), element.Context());
            }

        public static void TraceSurroundElement(this TraceSource ts, SElement element) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Surround '{0}' ({1}) element in '{2}' ({3}).", element.Name.ToString(), element.Context(), element.Parent.XPath, element.Parent.Context());
            }

        public static void TraceConstructedElement(this TraceSource ts, SElement element, SElement ancestor, int position) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Build '{0}' element in '{1}' ({2}) in position {3}.", element.Name.ToString(), ancestor.Name.ToString(), ancestor.Context(), position.ToString());
            }

        public static void TraceConstractedElement(this TraceSource ts, SElement element, SElement parent) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Build '{0}' element in '{1}' ({2}).", element.Name.ToString(), parent.Name.ToString(), parent.Context());
            }

        public static void TraceIgnoreElement(this TraceSource ts, SElement element, SElement ancestor) {
            Debug.Assert(ts != null);
            ts.TraceInformation("Ignore '{0}' ({1}) element in '{2}' ({3}) under validation rule.", element.Name.ToString(), element.Context(), ancestor.Name.ToString(), ancestor.Context());
            }

        private static string GetElementName(SElement element) {
            if (element.Name == SName.Empty) {
                if (element.DName == null)
                    return element.NodeType.ToString();
                else
                    return element.DName.ToString();
                }
            else
                return element.Name.ToString();
            }
        }
    }
